import React, { useContext, useEffect, useMemo } from 'react';
// import debounce from 'lodash.debounce';
import dayjs from 'dayjs';
import {
  Button,
  Checkbox,
  DatePicker,
  Input,
  InputNumber,
  Radio,
  Select,
  Switch,
  TimePicker,
} from '../index';

import { PlusOutlined } from '@ant-design/icons';
import en_GB from 'antd/lib/date-picker/locale/en_GB';
import zh_CN from 'antd/lib/date-picker/locale/zh_CN';
import { prefix } from '../config';
import {
  checkType,
  createUniqueId,
  getElementSize,
  getFormat,
  getPrefixCls,
} from '../utils';
import FilterContext, { filterContext, UPDATE_FILTER } from './context/filter';
import './style/TableFilter.less';

import type { AnyObject, ItemProps, Props, Widget, WidgetProps } from './type';

const dateFormat = 'YYYY-MM-DD';
const timeFormat = 'HH:mm:ss';
const prefixCls = getPrefixCls(prefix.tableFilter);

function InternalFilter(props: Props) {
  const { list = [], style, id } = props;
  const {
    filter: {
      id: tableFilterId,
      oneWidth,
      total,
      rowNum,
      minRowNum,
      isExpand,
      colSizes,
    },
    dispatch,
  } = useContext<any>(filterContext);
  const filterId = useMemo(
    () => id || tableFilterId || createUniqueId(prefixCls),
    [tableFilterId, id],
  );
  // 无children时，生成配置项的params
  const params: AnyObject = useMemo(() => {
    if (!props.children && !!list.length) {
      return list.reduce((res, item) => {
        const { name, value } = item;
        res[name] = value;
        return res;
      }, {} as AnyObject);
    }
    return {};
  }, [props.children, list]);
  const widgets = useMemo(() => {
    const widgets: {
      [key in Widget]: (widgetProps: WidgetProps) => JSX.Element;
    } = {
      input: (widgetProps: WidgetProps) => {
        const { name, value, props } = widgetProps;
        return (
          <Input
            placeholder={'请输入'}
            {...props}
            value={value}
            onChange={(e: any) =>
              widgetProps.onChange && widgetProps.onChange(name, e.target.value)
            }
          />
        );
      },
      switch: (widgetProps: WidgetProps) => {
        const { name, value, props } = widgetProps;
        return (
          <Switch
            {...props}
            checked={!!value}
            onChange={(checked) =>
              widgetProps.onChange &&
              widgetProps.onChange(name, checked ? 1 : 0)
            }
          />
        );
      },
      select: (widgetProps: WidgetProps) => {
        const { name, value, options, props } = widgetProps;

        return (
          <Select
            value={value}
            options={options}
            onChange={(v: any) =>
              widgetProps.onChange && widgetProps.onChange(name, v)
            }
            {...props}
          />
        );
      },
      checkboxes: (widgetProps: WidgetProps) => {
        const { name, value, options, props } = widgetProps;
        const isArray = checkType(value, 'array');

        return (
          <Checkbox.Group
            value={isArray ? value : !!value ? value.split(',') : []}
            options={options}
            onChange={(e: any) => {
              widgetProps.onChange && widgetProps.onChange(name, e.join(','));
            }}
            {...props}
          />
        );
      },
      radio: (widgetProps: WidgetProps) => {
        const { name, value, options, props } = widgetProps;

        return (
          <Radio.Group
            value={value}
            options={options}
            onChange={(e: any) =>
              widgetProps.onChange && widgetProps.onChange(name, e.target.value)
            }
            {...props}
          />
        );
      },
      number: (widgetProps: WidgetProps) => {
        const { name, value = [], props } = widgetProps;

        return (
          <>
            <InputNumber
              placeholder="最小值"
              width={80}
              value={value[0]}
              onChange={(v) =>
                widgetProps.onChange &&
                widgetProps.onChange(name, [v, value[1]])
              }
              {...props}
            />
            <span style={{ padding: '0 10px' }}>-</span>
            <InputNumber
              placeholder="最大值"
              width={80}
              value={value[1]}
              onChange={(v) =>
                widgetProps.onChange &&
                widgetProps.onChange(name, [value[0], v])
              }
              {...props}
            />
          </>
        );
      },
      date: (widgetProps: WidgetProps) => {
        const defaultPicker = 'date';
        const { name, value = [], props = {} } = widgetProps;
        const {
          format = dateFormat,
          picker = defaultPicker,
          ...restProps
        } = props;
        const datePickerFormat = getFormat(props.picker) || format;
        const datePicker = picker === 'dateTime' ? defaultPicker : picker;
        const showTime = picker === 'dateTime';
        const dates = value
          .filter((date: string) => !!date)
          .map((date: string) => dayjs(dayjs(date).format(format), format));

        return (
          <DatePicker.RangePicker
            format={datePickerFormat}
            showTime={showTime}
            picker={datePicker}
            value={dates}
            locale={
              window.localStorage.getItem('language') === 'zh-CN'
                ? zh_CN
                : en_GB
            }
            onChange={(_, dateString: string) => {
              widgetProps.onChange && widgetProps.onChange(name, dateString);
            }}
            {...restProps}
          />
        );
      },
      time: (widgetProps: WidgetProps) => {
        const { name, value = [], props = {} } = widgetProps;
        const { format = timeFormat, ...restProps } = props;
        const timePickerFormat = getFormat('time') || format;
        const dates = value
          .filter((date: string) => !!date)
          .map((date: string) => dayjs(dayjs(date).format(format), format));

        return (
          <TimePicker.RangePicker
            format={timePickerFormat}
            value={dates}
            onChange={(_, dateString: string) => {
              widgetProps.onChange && widgetProps.onChange(name, dateString);
            }}
            {...restProps}
          />
        );
      },
    };
    return widgets;
  }, []);
  const defaultWidgetsColSize: { [key in Widget]: number } = useMemo(() => {
    return {
      input: 1,
      switch: 1,
      select: 1,
      checkboxes: 1,
      radio: 1,
      number: 2,
      date: 2,
      time: 2,
    };
  }, []);

  const isCanExpand = total > rowNum - 1;

  const setResize = () => {
    const totalWidth = getElementSize(
      document.getElementById(filterId) as Element,
      'width',
    );
    const num = Math.floor(totalWidth / oneWidth);
    dispatch({
      type: UPDATE_FILTER,
      payload: { rowNum: num > 0 ? num : minRowNum },
    });
  };
  useEffect(() => {
    dispatch({ type: UPDATE_FILTER, payload: { id: filterId } });
    window.addEventListener('resize', setResize);
    return () => window.removeEventListener('resize', setResize);
  }, []);
  useEffect(() => {
    setTimeout(() => {
      setResize();
    }, 300);
  }, [filterId, document.getElementById(filterId)]);

  useEffect(() => {
    const total = colSizes?.reduce((result: number, col: number) => {
      result += col;
      return result;
    }, 0);
    dispatch({ type: UPDATE_FILTER, payload: { total } });
  }, [colSizes.length]);

  const setIsExpand = (isExpand = false) => {
    dispatch({ type: UPDATE_FILTER, payload: { isExpand } });
  };
  const getWidget = (type: Widget) => {
    return widgets[type] || widgets.input;
  };

  return (
    <div id={filterId} className={prefixCls} style={style}>
      <div className={`${prefixCls}Form`}>
        {props.children ||
          list.map((item, i) => {
            const {
              name,
              type,
              value,
              label,
              colSize,
              props,
              options = [],
            } = item;
            const Widget = getWidget(type);
            const defaultColSize = defaultWidgetsColSize[type];
            return (
              <Filter.Item
                label={label}
                colSize={colSize || defaultColSize}
                index={i}
                key={i}
              >
                <Widget
                  name={name}
                  value={value}
                  options={options}
                  props={props}
                  onChange={item.onChange}
                />
              </Filter.Item>
            );
          })}

        <div
          className={`${prefixCls}Item`}
          style={{ width: `${Math.floor(100 / rowNum)}%` }}
        >
          {isCanExpand && (
            <div
              className={`${prefixCls}Button`}
              onClick={() => setIsExpand(!isExpand)}
            >
              <span className={`${prefixCls}ButtonText`}>
                {isExpand ? '收起' : '展开'}
              </span>
            </div>
          )}
          <div className={`${prefixCls}Button`}>
            <span
              className={`${prefixCls}ButtonText`}
              onClick={() => props.onReset && props.onReset(params)}
            >
              重 置
            </span>
          </div>

          <Button
            className={`${prefixCls}Button`}
            buttonType="active-default"
            onClick={() => props.onSearch && props.onSearch(params)}
          >
            查 询
          </Button>
        </div>
      </div>
      {!!props.buttons && !!props.buttons.length && (
        <div className={`${prefixCls}Tools`}>
          {props.buttons.map((item, i) => {
            const { input: text } = item;
            return (
              <Button
                key={i}
                icon={<PlusOutlined />}
                className={`${prefixCls}ToolsItem`}
                type="primary"
                onClick={() => item.fn?.({ operate: item.key })}
              >
                {text}
              </Button>
            );
          })}
        </div>
      )}
    </div>
  );
}

function Filter(props: Props) {
  return (
    <FilterContext>
      <InternalFilter {...props} />
    </FilterContext>
  );
}
function FilterItem(props: ItemProps) {
  const { index, label, colSize = 1 } = props;
  const {
    filter: { rowNum, isExpand, colSizes },
    dispatch,
  } = useContext<any>(filterContext);
  // 计算每个表单项百分比
  const colWidth = Math.floor(100 / rowNum) * colSize;

  useEffect(() => {
    colSizes[index] = colSize;

    dispatch({ type: UPDATE_FILTER, payload: { colSizes } });
  }, [index, colSize]);

  const getCurIndexTotalSize = (index: number) => {
    return colSizes
      .slice(0, index)
      .reduce((res: number, cur: number) => (res += cur), 0);
  };
  // 表单项显示条件，表单展开，或者收起时当前表单项累计占比小于行数，
  const isShow = getCurIndexTotalSize(index + 1) < rowNum || isExpand;

  return (
    <div
      className={`${prefixCls}Item`}
      style={{ display: isShow ? 'flex' : 'none', width: `${colWidth}%` }}
    >
      <div className={`${prefixCls}ItemsBox`}>
        <span className={`${prefixCls}Title`}>{label}</span>
        <div className={`${prefixCls}FormItem`}>{props.children}</div>
      </div>
    </div>
  );
}
Filter.Item = FilterItem;
export default Filter;
